﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;

using System.IO;
using System.Security.AccessControl;
using System.Web;
using System.Web.Script.Serialization;
using DataModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web.Hosting;
using System.Diagnostics;

namespace iTrafficServer
{
    public class Upload : IHttpHandler
    {
        iTrafficEntities model = new iTrafficEntities();
        private readonly JavaScriptSerializer js = new JavaScriptSerializer();

        public class FilesStatus
        {
            public string thumbnail_url { get; set; }
            public string name { get; set; }
            public string url { get; set; }
            public int size { get; set; }
            public string type { get; set; }
            public string delete_url { get; set; }
            public string delete_type { get; set; }
            public string error { get; set; }
            public string progress { get; set; }
        }

        public bool IsReusable { get { return false; } }
        public void ProcessRequest(HttpContext context)
        {
            var r = context.Response;
            //ingestPath = @"C:\temp\ingest\";

            r.AddHeader("Pragma", "no-cache");
            r.AddHeader("Cache-Control", "private, no-cache");

            HandleMethod(context);
        }

        private void HandleMethod(HttpContext context)
        {
            switch (context.Request.HttpMethod)
            {
                case "HEAD":
                case "GET":
                    string action = context.Request["action"];
                    if (action == "delete")
                        DeleteFile(context);
                    else
                        ServeFile(context);
                    break;

                case "POST":
                    UploadFile(context);
                    break;

                case "DELETE":
                    DeleteFile(context);
                    break;

                default:
                    context.Response.ClearHeaders();
                    context.Response.StatusCode = 405;
                    break;
            }
        }

        private void DeleteFile(HttpContext context)
        {
            try
            {
                string filePath = HostingEnvironment.MapPath("~/App_Data/") + context.Request["f"];
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }

                filePath = HostingEnvironment.MapPath("~/App_Data/Thumbnail/") + context.Request["f"];
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }

                string strId = context.Request["id"];
                int id = Int32.Parse(strId);
                HotPoints_Photos photo = model.HotPoints_Photos.Single(p => p.Id == id);
                model.HotPoints_Photos.DeleteObject(photo);
                model.SaveChanges();
            }
            catch (Exception ex)
            {
                //use log4.net
            }
        }

        private void UploadFile(HttpContext context)
        {
            var statuses = new List<FilesStatus>();
            var headers = context.Request.Headers;

            if (string.IsNullOrEmpty(headers["X-File-Name"]))
            {
                UploadWholeFile(context, statuses);
            }
            else
            {
                UploadPartialFile(headers["X-File-Name"], context, statuses);
            }

            //WriteJsonIframeSafe(context, statuses);
        }

        private void CreateThumbnail(string originalFile, int w, int h)
        {
            Image image = null;
            try
            {
                image = Image.FromFile(originalFile);
            }
            catch (Exception ex)
            {
                //Tong vao trong EventLog
            }
            float tyle = (float)image.Width / image.Height;
            if (tyle <= 0)
            {

                h = w;
                w = Convert.ToInt32(w * tyle);
            }
            else
            {
                h = Convert.ToInt32(w / tyle);
            }
            Image newImage = image.GetThumbnailImage(w, h, null, IntPtr.Zero);

            string saveFileLocation = HostingEnvironment.MapPath("~/App_Data/Thumbnail/") +
                                Path.GetFileName(originalFile);

            string extentionFile = originalFile.Substring(originalFile.IndexOf(".") + 1);
            ImageFormat format = new ImageFormat(new Guid());
            if (extentionFile == "jpg")
            {
                format = ImageFormat.Jpeg;
            }
            else if (extentionFile == "bmp")
            {
                format = ImageFormat.Bmp;
            }
            else if (extentionFile == "gif")
            {
                format = ImageFormat.Gif;
            }
            else if (extentionFile == "png")
            {
                format = ImageFormat.Png;
            }
            newImage.Save(saveFileLocation, format);
            image.Dispose();
        }

        private void UploadPartialFile(string originalFileName, HttpContext context, List<FilesStatus> statuses)
        {
            if (context.Request.Files.Count != 1) throw new HttpRequestValidationException("Attempt to upload chunked file containing more than one fragment per request");

            var inputStream = context.Request.Files[0].InputStream;

            string extenstionFileName = originalFileName.Substring(originalFileName.IndexOf(".") + 1);
            string savedFileName = string.Format("{0}.{1}", Guid.NewGuid(), extenstionFileName);
            string fullSaveFilePath = HostingEnvironment.MapPath("~/App_Data/") + savedFileName;

            using (var fs = new FileStream(fullSaveFilePath, FileMode.Append, FileAccess.Write))
            {
                var buffer = new byte[1024];

                var l = inputStream.Read(buffer, 0, 1024);
                while (l > 0)
                {
                    fs.Write(buffer, 0, l);
                    l = inputStream.Read(buffer, 0, 1024);
                }
                fs.Flush();
                fs.Close();
            }

            statuses.Add(new FilesStatus
            {
                thumbnail_url = "Thumbnail.ashx?f=" + savedFileName,
                url = "Upload.ashx?f=" + savedFileName,
                name = savedFileName,
                size = (int)(new FileInfo(savedFileName)).Length,
                type = "image/png",
                delete_url = "Upload.ashx?f=" + savedFileName,
                delete_type = "DELETE",
                progress = "1.0"
            });

            #region Use EF4 to save to db
          //  User user1 = model.Users.First();
            // get object User
            object userid = context.Request.Form["userid"];
            int id = 0;
            if (userid != null)
            {
                id = Int32.Parse((string)userid);
            }

            object levelId = context.Request.Form["levelId"];
            int _levelId = 0;
            if (levelId != null)
            {
                _levelId = Int32.Parse((string)levelId);
            }

            object hotPointId = context.Request.Form["hotPointId"];
            int _hotpointId = 0;
            if (hotPointId != null)
            {
                _hotpointId = Int32.Parse((string)hotPointId);
            }


            HotPoints_Photos newPhoto = new HotPoints_Photos
            {
                OriginalFileName = originalFileName,
                FileName = savedFileName,
                Likes = 0,
                Dislikes = 0,
                ContentType = "image",
              //  User = user1,
                User = model.Users.Single(u => u.Id == id),
                tbl_HotPoints_Levels = model.HotPoints_Levels.Single(l => l.Id == _levelId),
                tbl_HotPoints = model.HotPoints.Single(p => p.Id == _hotpointId),
                Title = "",
                UploadTime = System.DateTime.Now,
            };
            try
            {
                object longitude = context.Request.Form["Longitude"];
                if (longitude != null) newPhoto.Longitude = double.Parse((string)longitude);
            }
            catch { }
            try
            {
                object latitude = context.Request.Form["Latitude"];
                if (latitude != null) newPhoto.Latitude = double.Parse((string)latitude);
            }
            catch { }
            #endregion
            if (CheckExtensionFileIsImage(extenstionFileName))
                CreateThumbnail(fullSaveFilePath, 150, 90);
        }

        private bool CheckExtensionFileIsImage(string extension)
        {
            if (extension.ToLower() == "jpg" || extension.ToLower() == "png"
               || extension.ToLower() == "bmp" || extension.ToLower() == "png"
               || extension.ToLower() == "tif" || extension.ToLower() == "gif")
                return true;
            else
                return false;
        }

        private void UploadWholeFile(HttpContext context, List<FilesStatus> statuses)
        {
            // object _longitude = context.Request.Form["Longitude"];
            // object _latitude = context.Request.Form["Latitude"];
            // if (longitude != null) newPhoto.Longitude = double.Parse((string)longitude);
            for (int i = 0; i < context.Request.Files.Count; i++)
            {
                var file = context.Request.Files[i];

                string originalFileName = Path.GetFileName(file.FileName);
                string extenstionFileName = originalFileName.Substring(originalFileName.LastIndexOf(".") + 1);
                string savedFileName = string.Format("{0}.{1}", Guid.NewGuid(), extenstionFileName);
                string fullSaveFilePath = HostingEnvironment.MapPath("~/App_Data/") + savedFileName;

                file.SaveAs(fullSaveFilePath);

                if (CheckExtensionFileIsImage(extenstionFileName))
                    CreateThumbnail(fullSaveFilePath, 150, 90);

                #region Use EF4 to save to db
                //  User user1 = model.Users.First();

                // get object User
                object userid = context.Request.Form["userid"];
                int id = 0;
                if (userid != null)
                {
                    id = Int32.Parse((string)userid);
                }

                object levelId = context.Request.Form["levelId"];
                int _levelId = 0;
                if (levelId != null)
                {
                    _levelId = Int32.Parse((string)levelId);
                }

                object hotPointId = context.Request.Form["hotPointId"];
                int _hotpointId = 0;
                if (hotPointId != null)
                {
                    _hotpointId = Int32.Parse((string)hotPointId);
                }
                HotPoints_Photos newPhoto = new HotPoints_Photos    
                {
                    OriginalFileName = originalFileName,
                    FileName = savedFileName,
                    Likes = 0,
                    Dislikes = 0,
                    ContentType = "image",
                    //  User = user1,
                    User = model.Users.Single(u => u.Id == id),
                    tbl_HotPoints = model.HotPoints.Single(p => p.Id == _hotpointId),
                    tbl_HotPoints_Levels = model.HotPoints_Levels.Single(l => l.Id == _levelId),
                    Title = "",
                    UploadTime = System.DateTime.Now,
                };
                try
                {
                    object longitude = context.Request.Form["Longitude"];
                    if (longitude != null) newPhoto.Longitude = double.Parse((string)longitude);
                }
                catch { }
                try
                {
                    object latitude = context.Request.Form["Latitude"];
                    if (latitude != null) newPhoto.Latitude = double.Parse((string)latitude);
                }
                catch { }
                #endregion


                model.AddToHotPoints_Photos(newPhoto);
                model.SaveChanges();

                statuses.Add(new FilesStatus
                {
                    thumbnail_url = "Thumbnail.ashx?f=" + savedFileName,
                    url = "Upload.ashx?f=" + savedFileName,
                    name = savedFileName,
                    size = file.ContentLength,
                    type = "image/png",
                    delete_url = string.Format("Upload.ashx?action=delete&f={0}&id={1}", newPhoto.FileName, newPhoto.Id),
                    delete_type = "GET",
                    progress = "1.0"
                });
            }
        }

        //private void WriteJsonIframeSafe(HttpContext context, List<FilesStatus> statuses) {
        //    context.Response.AddHeader("Vary", "Accept");
        //    try {
        //        if (context.Request["HTTP_ACCEPT"].Contains("application/json")) {
        //            context.Response.ContentType = "application/json";
        //        } else {
        //            context.Response.ContentType = "text/plain";
        //        }
        //    } catch {
        //        context.Response.ContentType = "text/plain";
        //    }

        //    var jsonObj = js.Serialize(statuses.ToArray());
        //    context.Response.Write(jsonObj);
        //}

        private void ServeFile(HttpContext context)
        {
            if (string.IsNullOrEmpty(context.Request["f"])) ListCurrentFiles(context);
            else DeliverFile(context);
        }

        private void DeliverFile(HttpContext context)
        {
            var filePath = HostingEnvironment.MapPath("~/App_Data/") + context.Request["f"];
            if (File.Exists(filePath))
            {
                string fileName = Path.GetFileName(filePath);
                string extension = fileName.Substring(fileName.IndexOf(".") + 1);
                if (extension == "jpg" || extension == "png")
                {
                    context.Response.ContentType = "image/jpeg";
                    context.Response.WriteFile(filePath);
                }
                else
                {
                    context.Response.ContentType = "application/octet-stream";
                    context.Response.WriteFile(filePath);
                    context.Response.AddHeader("Content-Disposition", "attachment, filename=\"" + context.Request["f"] + "\"");
                }

            }
            else
            {
                context.Response.StatusCode = 404;
            }
        }

        private void ListCurrentFiles(HttpContext context)
        {
            var files = new List<FilesStatus>();
            foreach (HotPoints_Photos p in model.HotPoints_Photos)
            {
                files.Add(new FilesStatus
                {
                    thumbnail_url = "Thumbnail.ashx?f=" + p.FileName,
                    url = "Upload.ashx?f=" + p.FileName,
                    name = p.FileName,
                    size = (int)111,
                    type = "image/png",
                    delete_url = string.Format("Upload.ashx?action=delete&f={0}&id={1}", p.FileName, p.Id),
                    delete_type = "GET"
                });
            }

            context.Response.AddHeader("Content-Disposition", "inline, filename=\"files.json\"");
            var jsonObj = js.Serialize(files.ToArray());
            context.Response.Write(jsonObj);
            context.Response.ContentType = "application/json";
        }
    }
}
